/**
 * @author 艾尼亚尔
 * @date 2025/8/7
 * @description 工具
 */

import {h, type Component} from 'vue'
import {NIcon} from "naive-ui";
import type {RouteLocationNormalized, RouteRecordRaw} from "vue-router";
import type {CustomMenuOption, ServerRouteItem} from '@/types/router';

import iconData from "@/utils/icons.ts";
import {getLocalStorage} from "@/utils/storage.ts";

const Layout = () => import('@/layout')

/**
 * 处理icon
 * @param icon 图标
 */
export function renderIcon(icon: Component) {
    return () => h(NIcon, null, {default: () => h(icon)});
}


/**
 * 获取简易的路由对象
 * @param route
 */
export const getSimpleRoute = (route: RouteLocationNormalized): SimpleRoute => {
    const {fullPath, hash, meta, name, params, path, query} = route;
    return {fullPath, hash, meta, name, params, path, query};
}

/**
 * 处理路由的名称
 * @param meta
 */
export const getTrimmedTitle = (meta: Record<string, unknown>): string => {
    const title = meta.title;
    return typeof title === 'string' ? title.replace(/\s/g, '') : '';
};


/**
 * 递归菜单数据格式
 * @param routerMap
 */
export const generatorMenu = (routerMap: RouteRecordRaw[]): CustomMenuOption[] => {
    const res: Array<CustomMenuOption> = [];
    routerMap.forEach((item: RouteRecordRaw) => {
        // 只过滤 hideInMenu 为 true 的s
        if (item.meta?.hideInMenu === true) return;

        // 如果有 children，递归处理
        let children: CustomMenuOption[] = [];
        if (item.children && item.children.length > 0) {
            children = generatorMenu(item.children);
        }
        // 如果只有一个子级，直接返回这个子级（提升）
        if (children.length === 1) {
            res.push(children[0]);
            return;
        }
        // 只为有 meta.title 的节点生成菜单项
        if (item.meta?.title) {
            const menu_icon: string = String(item.meta?.icon ?? 'tabler-List');
            const currentMenu: CustomMenuOption = {
                label: typeof item.meta.title === 'string'
                    ? item.meta.title
                    : String(item.meta.title), // 强制转换
                key: item.name as string,
                icon: renderIcon(iconData[menu_icon]),
            };
            if (children.length > 0) {
                currentMenu.children = children;
            }
            res.push(currentMenu);
        } else if (children.length > 0) {
            // 如果自己没有 title，但有 children，则把 children 提升上来
            res.push(...children);
        }
    });
    return res;
}

/**
 * 处理后台传过来的菜单路由数据
 * @param menuMap
 */
let viewsModules: ViewsModules;
const view_path:string='/src/views'
export const generateRoutesByServer = (menuMap: ServerRouteItem[]): RouteRecordRaw[] => {
    const res: RouteRecordRaw[] = []
    viewsModules = viewsModules || import.meta.glob(`/src/views/**/*`);
    menuMap.map((item: ServerRouteItem) => {
        let component: Component | (() => Promise<{ default: Component }>) | undefined
        if (item.component === 'Layout') {
            component = Layout;
        } else {
            component = dynamicImport(viewsModules, item.component);
        }
        const route = {
            path: item.path,
            name: item.name,
            component: component,
            meta: {
                title: item.meta?.title,
                hideInMenu: Boolean(item.meta?.hide_in_menu),
                ...(item.meta?.icon && {icon: item.meta.icon}),
            },
            ...(item.children?.length && {
                children: generateRoutesByServer(item.children)
            })
        } as RouteRecordRaw;
        res.push(route);
    })
    return res;
}

/**
 * 动态导入页面
 */
export const dynamicImport = (
    viewsModules: Record<string, () => Promise<Recordable>>,
    component: string
) => {
    const keys = Object.keys(viewsModules);
    const matchKeys = keys.filter((key) => {
        const k = key.replace(view_path, '');
        return k === component + "/index.ts" || k === component;
    });
    if (matchKeys?.length === 1) {
        const matchKey = matchKeys[0];
        return viewsModules[matchKey];
    }
    if (matchKeys?.length > 1) {
        console.warn(
            '请不要创建“.vue”和“.ts”视图文件夹下相同层次目录中具有相同文件名的文件。这将导致动态引入失败'
        );
        return;
    }
};


/**
 * 指定权限是否存在
 * @param permission 权限值 如:user:create
 * @return {boolean} true:存在  false:不存在
 */
export const hasPermission = (permission: string): boolean => {
    const authorities: string[] | null = getLocalStorage('authorities');
    return authorities?.includes(permission) ?? false;
}

/**
 * 检查是否存在任意所需的权限
 * @param permissions - 待检查的权限数组
 * @returns 若至少有一个权限被授予则返回true
 */
export const hasAnyPermission = (permissions: readonly string[]): boolean => {
    return permissions.some(hasPermission);
};

/**
 * 检查对象数组中每个元素的权限
 * @param items 待检查的对象数组
 * @param getPermission 从对象中提取权限标识的函数
 * @returns 对应每个元素的权限布尔数组
 */
export const checkPermissionForItems = <T extends Record<string, unknown>>(
    items: readonly T[] | string[],
    getPermission: (item: T) => string
): readonly boolean[] => {
    return (items as T[]).map(item => hasPermission(getPermission(item)));
};


/**
 * HEX → rgba(...) 字符串
 * @param hex 形如 #RRGGBB 或 #RGB
 * @param alpha 透明度 0~1，默认 1
 * @example
 */
export const hexToRgba = (hex: string, alpha: number = 1): string => {
    let str = hex.replace(/^#/, '');

    // 把 3 位扩展成 6 位
    if (str.length === 3) {
        str = str.replace(/./g, '$&$&');
    }
    if (!/^([0-9a-f]{6})$/i.test(str)) {
        throw new Error(`Invalid HEX color: ${hex}`);
    }

    const num = parseInt(str, 16);
    const r = (num >>> 16) & 0xff;
    const g = (num >>> 8) & 0xff;
    const b = num & 0xff;

    return `rgba(${r}, ${g}, ${b}, ${alpha})`;
}

/**
 * 对象转换URL 查询字符串
 * @param obj
 */
export const objectToQueryString = (obj: Record<string, unknown>): string => {
    return Object.entries(obj)
        .filter(([, val]) =>
            ['string', 'number', 'boolean'].includes(typeof val)
        )
        .map(
            ([key, val]) =>
                `${encodeURIComponent(key)}=${encodeURIComponent(String(val))}`
        )
        .join('&')
}


/**
 * 扁平化树，支持自定义父级字段名和子级字段名
 * @param data        树形数据
 * @param parentKey   根节点默认值
 * @param keyField    父级标识字段
 * @param parentField 子级接收父级 id 的字段
 */
export function flattenTreeWithParent<T extends PermissionItem>(
    data: T[],
    parentKey: number = 0,
    keyField: keyof T = 'key' as keyof T,
    parentField: keyof FlattenPermissionItem = 'p_id' as keyof FlattenPermissionItem
): FlattenPermissionItem[] {
    return data.flatMap(node => {
        const {children, ...rest} = node;

        const item = {
            ...rest,
            [parentField]: parentKey
        } as unknown as FlattenPermissionItem; // 先转为 unknown，再转为目标类型

        const childKey = node[keyField] as number;

        return [
            item,
            ...(children ? flattenTreeWithParent(children, childKey, keyField, parentField) : [])
        ];
    });
}


/**
 * 数组a的元素是否在数组b中存在
 * @param a 数组a
 * @param b 数组b
 */
export const isSubset = <T>(a: T[], b: T[]): boolean => {
    return a.some(val => b.includes(val));
}


/**
 * 将 MB 转换为易读字符串
 * @param mb 兆字节数
 * @returns 例如 512 -> "512 MB"，1245 -> "1.22 GB"，1024 -> "1 GB"
 */
export const formatSize=(mb: number): string =>{
    if (mb < 1024) return `${mb}MB`;
    const gb = mb / 1024;
    // 小数部分全为 0
    if (Number.isInteger(gb)) {
        return `${gb}GB`;
    }
    return `${gb.toFixed(2)}GB`;
}

/**
 * 检测输入是否为维吾尔语
 * @param text 待检测的文本
 * @returns 如果是维吾尔语返回 true，否则返回 false
 */
export function isUyghur(text: string | null | undefined): boolean {
    if (!text || text.trim().length === 0) {
        return false;
    }
    // 维吾尔语使用的Unicode范围
    // 主要使用阿拉伯文字符 (U+0600-U+06FF)
    // 包含维吾尔语特有的字符
    const uyghurRegex = /[\u0600-\u06FF\u0750-\u077F\u08A0-\u08FF\uFB50-\uFDFF\uFE70-\uFEFF]/;
    // 检查文本中是否包含维吾尔语字符
    return uyghurRegex.test(text);
}